Aqua Platform Enterprise MicroEnforcerのサイドカーでFargateに起動したDVWAを防御してみた
こんにちは!AWS事業本部コンサルティング部のたかくに(@takakuni_)です!
aqua社が提供しているAqua Platform の Enterprise版を試す機会がありましたのでECS-Fargate上に検証環境向けセットアップをおこない手順をまとめました。
Aqua Platformとは?
Aqua Platformはaqua社が提供するソリューションでコンテナとクラウドネイティブアプリのために開発された、 フルライフサイクルなセキュリティソリューションになります。
aqua コンテナ・クラウドネイティブアプリのためのセキュリティソリューション
記事の前提について
今回の記事は、Aqua社と交渉の上、検証用のトライアルアカウントを利用しています。
コンテナイメージや、セットアップ用のドキュメントなどは、公式ドキュメントアクセス用のアカウントが必要となりますのでご留意ください。
検証環境について
今回、ECS Fargateを利用して構築してあることを前提にしております。
FargateでMicroEnforcerを使う方法は2種類あります。
今回はサイドカーコンテナを立ち上げて連携する方法をご紹介します。アプリケーションコンテナに直接組み込む方法は以下をご覧ください。
全体の構成図は以下になります。順番に構成図のリソースを作っていきます。
VPCの構築
既に使用したいVPCが決まっていれば、この手順は飛ばしてもらって構いません。
構成図の通り、2AZ間でパブリック/プライベートサブネットを作成し、1つのAZでNAT Gatewayを作成する構成を作成しました。
図で表すと以下のリソースまで作成できました。
ECRの作成
ECSでコンテナを起動するためDocker Imageを保存するレジストリを作成します。
今回作成するレジストリは以下の3つです。
- aqua-console(Aqua ServerのDocker Image用)
- aqua-gateway(Aqua GatewayのDocker Image用)
- aqua-enforcer(Sidecar ContainerのDocker Image用)
- aqua-container(Application ContainerのDocker Image用)
同様に残り3つのレジストリも作成します。
イメージのプッシュ(Aqua Server/Gateway)
MicroEnforcerのセットアップにあたり、Aqua Server/Gatewayを立ち上げる必要があるため先に、Docker Imageのプッシュを行います。
作業手順は以下の通りです。
- Dockerイメージの取得を行うためAquaにログインします。
docker image pull
でイメージを取得します。- ECRへログイン
docker image tag
でイメージにタグ付けを行います。docker image push
でイメージをECRにプッシュします。
Aquaにログイン
docker login registry.aquasec.com
イメージ取得
docker pull registry.aquasec.com/console:2022.4
docker pull registry.aquasec.com/gateway:2022.4
ECRログイン
「XXXXXXXXXXXX」、「ap-northeast-1」はご自身のAWSアカウントIDとECRを作成したリージョンに置き換えてください。
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com
イメージタグ付け
docker image tag registry.aquasec.com/console:2022.4 XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-console:2022.4
docker image tag registry.aquasec.com/gateway:2022.4 XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-gateway:2022.4
イメージプッシュ
docker image push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-console:2022.4
docker image push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-gateway:2022.4
構成図としては以下まで作成できました。
Aqua Enterpriseのセットアップ
CloudFormationスタックの作成
aquaのガイドページに掲載されている手順に沿って導入を進めていきます。
※ ガイドページはログインが必要なページとなっております。
DEPLOY AQUA ENTERPRISE > Non-Kubernetes Platforms > Amazon Elastic Container Service (ECS)
こちらを参照すると、GitHubを参照するように記載がありますが迷って、問い合わせ確認したところ以下であることがわかりました。
GitHub - aquasecurity/deployments/server/ecs/cloudformation
上記のGitHubリポジトリからスタックの作成を行います。
READMEに構成が説明されており、以下のものが作成されます。
構築されるリソース
構築されるもの | 用途 |
---|---|
ALB | Aqua Server(Aqua Console)用のALB |
NLB | Aqua GatewayとAqua Server用のNLB |
Aqua Server (Aqua Console) | Fargateで起動するアプリケーションサーバ |
Aqua Gateway | Fargateで起動するAqua ServerとAqua Enforcerの通信を処理するコンポーネント |
Aqua Database | RDSインスタンス 起動する設定やセキュリティポリシー、ユーザ管理、ログ履歴を保存。別途構築のRDSの指定も可能 |
Secrets Manager | RDS接続情報の保存 |
AWS Lambda | Random String 生成用 |
Cloudwatch Logs | Console/enforcer/gateway、performance用の4個のロググループ と上記Lambdaのロググループ |
S3 | ALBのアクセスログ保管先バケット |
IAM | ECSのタスク用ロールと、Lambda用ロール |
各コンポーネントの詳細については以下のブログを参照ください。
参考までに今回は、以下のパラメーターを使用しました。
キー | 値 |
---|---|
VpcId | デプロイするVPCのID |
VpcCidr | 10.0.0.0/16 |
EcsInstanceSubnets | 2AZにまたがるプライベートサブネットを2つ選択 |
LbSubnets | 2AZにまたがるパブリックサブネットを2つ選択 |
SSLCert | ALBに紐づけるACMのARN |
Aqua LB Scheme | internet-facing |
Web Console Source | 0.0.0.0/0 |
AquaServerImage | XXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-console:2022.4 |
AquaGatewayImage | XXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-gateway:2022.4 |
ActiveActive | false |
RDS instance type | db.t3.medium |
RDS storage size (GB) | 50 |
Enable Multi-AZ RDS | false |
AuditRDS | No |
AuditRdsInstanceClass | db.t3.medium |
ClusterName | aqua-ecs |
ALBのレコード登録
ALBリスナーに設定した証明書のドメインでログインできるよう、Route53またはDNSサーバーのレコードを登録します。
私の場合は、Route53でドメインを管理しているため以下のエイリアスレコードを登録しました。
キー | 値 |
---|---|
レコード名 | ACMと同じドメイン |
レコードタイプ | Aレコード |
エイリアス | 有効 |
Application LoadBalancerのエイリアス | ALBのDNS名 |
構成図としては以下まで作成できました。
Aqua Consoleのセットアップ
Route53で登録したドメイン経由でALBにアクセスします。初回アクセス時は、ユーザー名とパスワードの登録を求められます。
今回は、検証のため以下の値を入力しました。
- ユーザー名:administrator
- パスワード:Admin1qaz@wsx
Enforcer Groupの作成
画面左ペインの「Administration」をクリックして、「Enforcers」をクリックします。
「Add Enforcer Group」をクリックして今回使用するMicroEnforcerのグループを作成します。
使用したパラメータは以下の通りです。
キー | 値 | 備考 |
---|---|---|
Enforcer Type | Aqua MicroEnforcer | |
Group Name | ECS-FargateMicroEnforcerGroup | |
Logical Name | ECS-FargateMicroEnforcerLGroup | |
Aqua Gateway | デフォルトの値(ip-10-0-135-9.ap-northeast-1.compute.internalなどの値) | |
Deployment Token | ECS-FargateMicroEnforcerDeploymentToken |
加えて、検知した際の挙動をブロックしたいため「Advanced settings」から「Enforcement Mode」を「Enforce」に変更します。
「Create Group」をクリックすると、Enforcer Groupが作成されます。
Aqua MicroEnforcerのセットアップ
サイドカー用イメージの作成
MicroEnforcerのサイドカー用のDockerfileのビルドに使うための作業ディレクトリを作成します。例:sidecar
MicroEnforcerのバイナリをAquaのドキュメントのリンクからダウンロードし作業ディレクトリの中に配置します。
policy.jsonとfirewall.jsonという空ファイルも作成します。
takakuni@sidecar % ls -ltr
total 33608
-rw-r--r--@ 1 takakuni.shinnosuke staff 925 3 29 20:29 Dockerfile
-rw-r--r--@ 1 takakuni.shinnosuke staff 0 3 29 20:31 firewall.json
-rw-r--r--@ 1 takakuni.shinnosuke staff 0 3 29 20:31 policy.json
-rw-r--r--@ 1 takakuni.shinnosuke staff 17203200 3 29 21:08 microenforcer
FROM alpine
COPY microenforcer /bin/microenforcer
USER root
RUN ["chmod", "+x", "/bin/microenforcer"]
RUN ["/bin/microenforcer", "aqua-init"]
VOLUME ["/.aquasec"]
# Include the next line to embed an Image Profile
ADD policy.json /.aquasec/policy/policy.json
# Include the next line to embed a Firewall Policy
ADD firewall.json /.aquasec/policy/firewall.json
COPY microenforcer /.aquasec/bin/microenforcer
RUN addgroup -g 11433 -S aqua && \
adduser -h /home/aqua -g "aqua user" -s /sbin/nologin -G aqua -S -u 11431 aqua
USER aqua
ENV LD_PRELOAD='/.aquasec/bin/$PLATFORM/slklib.so'
ENV AQUA_MICROENFORCER="1"
ENV AQUA_DEBUG_TYPE=STDOUT
LABEL name="Aqua MicroEnforcer" \
vendor="Aqua Security Software Ltd." \
summary="Aqua Security Microenforcer" \
description="The Aqua Security MicroEnforcer provides runtime protection." \
com.aquasec.component=microenforcer \
com.aquasec.baseimage=alpine \
product=aquasec \
maintainer="[email protected]"
Dockerイメージをビルドして、ECRにリポジトリにプッシュします。
イメージのビルド
docker image build -t aqua-enforcer:latest --platform x86_64 .
イメージのタグ付け
docker image tag aqua-enforcer:latest XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-enforcer:latest
イメージのプッシュ
docker image push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-enforcer:latest
アプリケーションコンテナの準備
今回は、DVWA(Damn Vulnerable Web Application)のDockerイメージを利用します。
Application Container用のECRリポジトリにDVWAのDockerイメージをプッシュします。
docker image pull vulnerables/web-dvwa
docker image tag vulnerables/web-dvwa:latest XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-container
docker image push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-container
Application Containerの起動
ENTRYPOINTの取得
Application ContainerのDockerイメージで実行される予定の「ENTRYPOINT」を取得します。
以下で取得した出力が「null」の場合、何も指定する必要はありません。
値が出力された場合、控えておきます。
docker image inspect XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-container:latest -f "{{json .Config.Entrypoint}}"
私の場合は、["/main.sh"]
が出力されました。
CMDの取得
同じくApplication ContainerのDockerイメージで実行される予定の「CMD」を取得します。
こちらも、取得した出力が「null」の場合、何も指定する必要はありません。
値が出力された場合、控えておきます。
docker image inspect XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-container:latest -f "{{json .Config.Cmd}}"
DockerイメージIDの取得
Application ContainerのDockerイメージで実行される予定の「CMD」を取得します。
値を控えておきます。
docker image inspect -f {{.Id}} XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-container:latest
タスク定義の作成
「Fargate」起動モードでタスク定義を作成します。
値は以下の通りで作成しました。(言及がないものは、デフォルト値です。)
設定 | 値 | 備考 |
---|---|---|
タスク定義名 | aqua-fargate-sidecar | |
タスクロール | ecsTaskExecutionRole | |
オペレーティングシステムファミリー | Linux | |
タスク実行ロール | ecsTaskExecutionRole | |
タスクメモリ (GB) | 0.5GB | |
タスク CPU (vCPU) | 0.25GB |
コンテナ設定(サイドカー)
タスク定義内のコンテナ設定です。
サイドカーコンテナは以下のように設定しました。
設定 | 値 | 備考 |
---|---|---|
コンテナ名 | aqua-sidecar-container | |
イメージ | XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-enforcer | |
基本(環境) | チェックを外す | 極めて短い時間で実行するため |
コンテナ設定(DVWA)
タスク定義内のコンテナ設定です。
アプリケーションコンテナ(DVWA)は以下のように設定しました。
設定 | 値 | 備考 |
---|---|---|
コンテナ名 | aqua-app-container | |
イメージ | XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/aqua-container | |
ポートマッピング | 80:tcp | |
エントリポイント(環境) | "/.aquasec/bin/microenforcer","/main.sh" | アプリケーションコンテナから見たサイドカーコンテナ上のmicroenforcerのパス、「ENTRYPOINTの取得」で控えた値 |
コマンド(環境) | 「CMDの取得」で控えた値、私の場合は「null」のため指定無し |
また、環境変数は以下を設定します。
設定 | 値 | 備考 |
---|---|---|
AQUA_SERVER | NLBのDNS:8444 | |
AQUA_TOKEN | ECS-FargateMicroEnforcerDeploymentToken | |
AQUA_IMAGE_ID | sha256:ab0d83586b6e8799bb549ab91914402e47e3bcc7eea0c5cdf43755d56150cc6a | 「DockerイメージIDの取得」で控えた値 |
LD_PRELOAD | '/.aquasec/bin/$PLATFORM/slklib.so' | ランタイムプロテクションへのパス |
最後に、「ストレージとログ」の「ボリュームソース」で、サイドカーコンテナのボリュームをマウントするため、以下を設定します。
設定 | 値 | 備考 |
---|---|---|
ソースコンテナ | aqua-sidecar-container | |
読み取り専用 | 無効 |
「新しいタスク定義の作成」の画面に戻り、画面下部の「作成」をクリックします。
サービスの作成
タスク定義が完了したため、サービスを起動しタスクを立ち上げていきます。
今回は、検証のため以下のように設定しました。
(とくに言及がないものは、デフォルト値で設定しています。)
設定 | 値 | 備考 |
---|---|---|
起動タイプ | FARGATE | |
オペレーティングシステムファミリー | Linux | |
タスク定義(ファミリー) | aqua-fargate-sidecar | |
タスク定義(リビジョン) | latest | |
サービス名 | aqua-fargate-sidecar-svc | |
タスクの数 | 1 | |
クラスター VPC | Aqua Enterpriseと同じVPC | 任意のVPCでOK |
サブネット | パブリックサブネット | 任意のサブネットでOK |
セキュリティグループ | 新しいセキュリティグループ | 80番ポートが開いているセキュリティグループを作成 |
サービスが作成されると「タスク定義」に従いコンテナが起動します。
アプリケーションコンテナが「RUNNING」、サイドカーコンテナが「STOPPED」になっていればOKです。
Aqua Consoleにログインすると、アプリケーションコンテナが検知されていることがわかります。
これで、AWSリソースの作成は完了しました。
動作検証
事前動作確認
アプリケーションコンテナ(DVWAコンテナ)へログインしてMicroEnforcerが動作するかどうか確認します。
ユーザー名、パスワードに以下を入力してログインします。
- ユーザー名:admin
- パスワード:password
「Command Injection」を開き、; /bin/cat /etc/passwd ;
を入力して送信すると。
/etc/passwd
が出力されました。
今回は、/bin/cat
がコンテナ内で実行されないようランタイムポリシーの機能の1つである「Executables Blocked」を使用して、/bin/cat
をブロックしてみようと思います。
他の機能も知りたいという方は以下のブログをご覧ください。
Runtime policyの編集
実際に制御を行うランタイムポリシーを編集します。
Aqua Consoleから「Policy」、「Runtime Policies」を選択します。
「Aqua default runtime policy」を選択して編集します。
ランタイムポリシーの設定変更手順は以下の通りです。
- 「Enforcement Mode」を「Enforce」に変更します。
- 「Controls」から「Executables Blocked」を選択します。
- 「Executables Blocked」で「/bin/cat」を追加します。
- 「Save」をクリックします。再起動を求められる画面で、「OK」を選択します。
これで、/bin/cat
の実行をコンテナ内でブロックしたため、/etc/passwd
が表示されなくなりました。
おわりに
以上、「Aqua Platform Enterprise MicroEnforcerのサイドカーでFargateに起動したDVWAを防御してみた」でした。
今回はサイドカータイプで実装しましたが、MicroEnforcerを直接アプリケーションコンテナに組み込むパターンもあるので是非ご覧いただければと思います。
以上、AWS事業本部コンサルティング部のたかくに(@takakuni_)でした!